# -*- coding: utf-8 -*- 
import wx
import socket, sys, threading,time
from pyDemin import *

class ClientKernel:
	def __init__(self,win):
		
		#Les threads
		self.th_R=-1
		self.th_E=-1
		
		#Les paramètres du joueur
		self.nom=""
		
		#Les paramètres de connexion
		self.port=8003
		self.ip="127.0.0.1"
		
		#Les paramètres du démineur
		self.lon=-1
		self.lar=-1
		self.nm=-1
		self.grille=-1
		
		#Les paramètres de partie
		self.nbj=-1
		self.maxj=-1

	def set_param_connexions(self,port,ip):
		self.port=port
		self.ip=ip
	
	def set_nom(self,nom):
		self.nom=nom
		
	def connect(self):
		#si retourne 1 la connexion a échouée
		#si retroune 2 la connexion existe déjà...
		#si retourne 0 all is fine !
		connexion = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		try:
			connexion.connect((self.host,self.port))
			print "Connexion etablie avec le serveur."
			if self.th_R == -1 and self.th_E == -1:
				self.th_R = ThreadReception(self.parent,connexion)
				self.th_E = ThreadEmission(self.parent,connexion)
				self.th_E.start()
				self.th_R.start()
			else:
				return 2
		except socket.error:
			print "Connexion failed"
			return 1
		return 0

	def clickG(self,x,y):
		self.th_E.envoiclikG(x,y)
	
	def clickD(self,x,y):
		self.th_E.envoiclikD(x,y)

	def disconnect(self):
		self.th_E.envoiFin()
		self.th_E._Thread__stop()
		self.th_R._Thread__stop()
		self.th_E=0
		self.th_R=0

	def set_nbj(self,nbj):
		self.nbj=nbj

	def set_maxj(self,maxj):
		self.maxj=maxj

	def get_nbj(self,nbj):
		return self.nbj

	def get_maxj(self,maxj):
		return self.maxj

	def testparam(self,nom,ip,port):
        #On teste la validité des chaines envoyées en paramètres !
		tx1_text=nom
		test1=False
		print len(tx1_text)
		if len(tx1_text)>0:
        #le nom doit juste être différent d'une chaine vide
			test1=True
		tx2_text=ip
		test2=False
		tx2_splitted=tx2_text.split(".")
		if len(tx2_splitted)==4:
        #l'adresse doit être comp. de 4 nb sép. par des pts
			try:
				for i in tx2_splitted: 
                         #hack pour test de la numéricité
					int(i)
					test2=True
			except:
				test2=False
		tx3_text=port
		test3=False
		print(tx3_text)
		try: 
                #hack pour tester la numéricité
			int(tx3_text)
			test3=True
		except:
			test3=False
		erreur=""
		if not test1:
			erreur+=" Le nom d'utilisateur n'est pas rempli ! "
		else:
			self.nom = tx1_text
		if not test2:
			erreur+=" L'adresse est dans un format incorrect ! "
		else:
			self.host = tx2_text
		if not test3:
			erreur+=" Le port n'est pas dans un format correct ! "
		else:
			self.port = int(tx3_text)
		if erreur <> "":
			return erreur
		else:
			return True
		
	def set_param_demin(self,lon,lar,nm):
		self.lon=lon
		self.lar=lar
		self.nm=nm
		self.grille=numpy.zeros((self.lon,self.lar))
	
	def update_grille(self,grille):
		self.grille=grille



class DeminWindow(wx.Panel):
#panel Minimum !
	def __init__(self, parent,ID,a,b,c):
		wx.Panel.__init__(self,parent,ID)
		self.SetSize(parent.GetClientSize())
		self.init_buffer()
                self.Bind(wx.EVT_PAINT,self.OnPaint)

	def OnPaint(self,evt):
		dc = wx.BufferedPaintDC(self,self.buffer)

	def init_buffer(self):
		w,h = self.GetClientSize()
		self.buffer = wx.EmptyBitmap(w,h)
		dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)

	def draw(self,dc,a,b):
		dc.Clear()	
class DeminWindow2(wx.Panel):
	def __init__(self, parent, ID,l,L,nm):#,deco):#,inf):
		wx.Panel.__init__(self,parent,ID)
		self.SetSize(parent.GetClientSize())
		self.L=L
		self.l=l
	#	self.deco=numpy.zeros((l,L))
		self.grille=numpy.zeros((self.L,self.l))
		for i in range(self.l):#on reconstruit la grille a partir de la nouvelle grille recue
			for j in range(self.L):
				self.grille[i,j]=-1
	#	self.inf=inf
		self.gw=0 #c'est sur le serveur que cette info est stockee, il faut aller la chercher on peut eventuellement updater la valeur du serveur dans cette variable de temps en temps.
		self.nm=nm
	
#		self.th_E=Thread_E
#		self.th_R=Thread_R
		self.init_buffer()
		self.Bind(wx.EVT_PAINT,self.OnPaint)
		self.Bind(wx.EVT_LEFT_DOWN,self.OnLeft)
		self.Bind(wx.EVT_RIGHT_DOWN,self.OnRight)
	
		
	
	def envoiM(self,event):
		self.th_E.envoiM(event.GetString())
##Il faut une fonction qui convertit le x et y de la position dans la fenêtre en un 
#numéro de ligne/colonne de case !
	def OnLeft(self,evt):
		x,y = evt.GetPosition()
		#ici traduction de x,y en case !
		self.th_E.envoiclikG(x,y)
		
	def OnRight(self,evt):
		x,y = evt.GetPosition()
		#ici traduction de x,y en case !
		self.th_E.envoiclikD(x,y)
	def OnPaint(self,evt):
		dc = wx.BufferedPaintDC(self,self.buffer)
	def init_buffer(self):
		w,h = self.GetClientSize()
		self.buffer = wx.EmptyBitmap(w,h)
		dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)
		self.draw(dc)
	def draw(self,dc):
		dc.Clear()
		dc.SetBrush(wx.Brush("red"))
		dc.SetPen(wx.Pen("black",1))
		k=0
		for i in range(self.l):
			for j in range(self.L):
				if self.grille[i,j]==-1:
					dc.SetBrush(wx.Brush("grey"))
					dc.DrawRectangle(i*600/self.l,j*600/self.L,600/self.l,600/self.L)
				elif self.grille[i,j]!=-1 or self.grille[i,j]!=-2:
					dc.DrawText("%d"%self.grille[i,j],i*600/self.l+11,j*600/self.L+7)
				else:
					dc.SetBrush(wx.Brush("grey"))
					dc.DrawRectangle(i*600/self.l,j*600/self.L,600/self.l,600/self.L)
					dc.SetBrush(wx.Brush("red"))
					dc.DrawLine(i*600/self.l+10,j*600/self.L+20,i*600/self.l+10,j*600/self.L+5)
					dc.DrawRectangle(i*600/self.l+10,j*600/self.L+5,10,7)
					dc.DrawLine(i*600/self.l+8,j*600/self.L+20,i*600/self.l+13,j*600/self.L+20)
					k+=1
		dc.DrawText("Nombre de mines restantes : %d"%(self.nm-k),20,620)
	
		b=wx.Button(self,-1,"quit",(550,625),(50,25))
		self.Bind(wx.EVT_BUTTON,self.fermerfenetre,b)

	def fermerfenetre(self,event):
		self.GetParent().Destroy()

class informations(wx.Panel):
	def __init__(self, parent, ID):#,deco):#,inf):
		wx.Panel.__init__(self,parent,ID)
		self.SetSize(parent.GetClientSize())
		self.stateclient=0
		self.nom="flo"
                self.host="127.0.0.1"
                self.port=80037
		self.ready=0
		self.nbJ=0
		self.maxJ=0
		self.parent=parent
		self.tx0=wx.StaticText(self,-1,"nom du joueur",(60,00))
                self.tx1=wx.TextCtrl(self,-1,"ff",(60,20),size=(340,20),style=wx.TE_PROCESS_ENTER)

		self.tx01=wx.StaticText(self,-1,"host",(60,40))
                self.tx2=wx.TextCtrl(self,-1,"127.0.0.1",(60,60),size=(340,20),style=wx.TE_PROCESS_ENTER) #style-> enter pas considere comme un caractere
                self.tx02=wx.StaticText(self,-1,"port",(60,80))
                self.tx3=wx.TextCtrl(self,-1,"80032",(60,100),size=(340,20),style=wx.TE_PROCESS_ENTER)

		self.st1=wx.Button(self,1,"start research",(100,140),(120,40))
		self.Bind(wx.EVT_BUTTON,self.go,id=1)
		self.tx4=wx.StaticText(self,-1,"",(60,180)) #on prépare la zone où il recevra le nombre de joueurs en ligne et tout !
		self.parent.CreateStatusBar()#cree la barre du bas de la fenetre
                self.parent.SetStatusText("")
                menubar=wx.MenuBar()
                menu=wx.Menu()
                menu.Append(101,"exit","quitte le programme")
                menubar.Append(menu,"fichier")
                self.parent.SetMenuBar(menubar)
                wx.EVT_MENU(self, 101,  self.TimeToQuit)
		self.stt=0#futur bouton start research
	def init_buffer(self):
		w,h = self.GetClientSize()
		self.buffer = wx.EmptyBitmap(w,h)
        def TimeToQuit(self, event):##### a ameliorer
		self.parent.th_E.envoiFin()
		self.parent.Close(True)#ferme la fenetre

	def updateLabel(self):
    		    self.SetStatusText("There are "+str(self.nbJ)+" players online. "+str(int(self.maxJ)-int(self.nbJ))+" waiting !")

	def testparam(self):#On teste la validité des chaines envoyées en paramètres !
		tx1_text=self.tx1.GetString(0,-1)
		test1=False
		print len(tx1_text)
		if len(tx1_text)>0:#le nom doit juste être différent d'une chaine vide
			test1=True
		tx2_text=self.tx2.GetString(0,-1)
		test2=False
		tx2_splitted=tx2_text.split(".")
		if len(tx2_splitted)==4:#l'adresse doit être composée de 4 éléments numériques séparés par des points
			try:
				for i in tx2_splitted: #hack pour test de la numéricité
					int(i)
					test2=True
			except:
				test2=False
		tx3_text=self.tx3.GetString(0,-1)
		test3=False
		print(tx3_text)
		try: #hack pour tester la numéricité
			int(tx3_text)
			test3=True
		except:
			test3=False
		erreur=""
		if not test1:
			erreur+=" Le nom d'utilisateur n'est pas rempli ! "
		else:
			self.nom = tx1_text
		if not test2:
			erreur+=" L'adresse est dans un format incorrect ! "
		else:
			self.host = tx2_text
		if not test3:
			erreur+=" Le port n'est pas dans un format correct ! "
		else:
			self.port = int(tx3_text)
		if erreur <> "":
			return erreur
		else:
			return True
		
	def bloqueControlesConnexion(self):
		self.tx1.Destroy()
		self.tx2.Destroy()
		self.tx3.Destroy()
		wx.StaticText(self,1,self.nom,(60,20))
		wx.StaticText(self,2,self.host,(60,60))
		wx.StaticText(self,3,str(self.port),(60,100))
	
	def libereControlesConnexion(self):
		self.tx1=wx.TextCtrl(self,-1,self.nom,(60,20),size=(340,20),style=wx.TE_PROCESS_ENTER)
		self.tx2=wx.TextCtrl(self,-1,self.host,(60,60),size=(340,20),style=wx.TE_PROCESS_ENTER) #style-> enter pas considere comme un caractere
		self.tx3=wx.TextCtrl(self,-1,str(self.port),(60,100),size=(340,20),style=wx.TE_PROCESS_ENTER)

	def modifyControlesConnexion(self,event):
		self.parent.th_E.envoiM("FIN")
		self.parent.th_E._Thread__stop()
		self.parent.th_R._Thread__stop()
		self.parent.th_R=0
		self.parent.th_E=0

		self.libereControlesConnexion()
		self.st1=wx.Button(self,1,"start research",(100,140),(120,40))
		self.Bind(wx.EVT_BUTTON,self.go,id=1)

	def start(self,event):
		self.stt.Destroy()
		self.st1.Destroy()
		self.parent.th_E.envoiOK()
		print "start enclenched"	
	#	event.GetEventObject().Destroy()


	def grillerecue(self,lon,lar,nm):
#		self.parent.grillerecue(lon,lar,nm)
		app2 = GameApp(lon, lar, nm, self.parent.th_E, self.parent.th_R)
		app2.MainLoop()
	def afficherStart(self):
		self.stt=wx.Button(self,2,"Start",(100,220),(120,40))
		self.Bind(wx.EVT_BUTTON,self.start,id=2)
		
	def go(self, event):
           self.testparam()
	   if self.testparam()==True :
                self.bloqueControlesConnexion()
		self.stateclient=1
		connexion = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		try:
			connexion.connect((self.host,self.port))
			print "Connexion etablie avec le serveur."
			self.ready=4
			if self.parent.th_R==0:
				self.parent.th_R = ThreadReception(self.parent,connexion)
			if self.parent.th_E==0:
				self.parent.th_E = ThreadEmission(self.parent,connexion)
			self.parent.th_E.start()
			self.parent.th_R.start()
			#self.tx4=wx.TextCtrl(self,3000,"",(60,130),size=(340,20),style=wx.TE_PROCESS_ENTER)
			#self.Bind(wx.EVT_TEXT_ENTER,self.sendmsg,tx4)
			event.GetEventObject().Destroy()
			self.st1=wx.Button(self,1,"Modify",(100,140),(120,40))
			self.Bind(wx.EVT_BUTTON,self.modifyControlesConnexion,id=1)
			self.parent.th_E.needNbjoueurs()
			#self.th_NBJ.start()
						
		except socket.error:
			print "La connexion a echoue."
			self.libereControlesConnexion()
			
			#sys.exit()
			#tx1=wx.TextCtrl(self,1000,"",(60,20),size=(340,20),style=wx.TE_PROCESS_ENTER)
			#self.Bind(wx.EVT_TEXT_ENTER,self.getnom,tx1)	
			#tx2=wx.TextCtrl(self,2000,"",(60,60),size=(340,20),style=wx.TE_PROCESS_ENTER) #style-> enter pas considere comme un caractere
			#self.Bind(wx.EVT_TEXT_ENTER,self.gethost,tx2)
			#tx3=wx.TextCtrl(self,3000,"",(60,100),size=(340,20),style=wx.TE_PROCESS_ENTER)
			#self.Bind(wx.EVT_TEXT_ENTER,self.getport,tx3)
	   else:
		   self.parent.th_E=0
		   self.parent.th_R=0
		   self.SetStatusText(self.testparam())
class PanInfFrame(wx.Frame):
	def __init__( self, parent, ID, title, pos=wx.DefaultPosition,size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE):
		wx.Frame.__init__(self, parent, ID, title, pos, size, style)
		self.SetAutoLayout(True)
		self.panInf=informations(self,102)
		self.th_R=0
		self.th_E=0
		self.panInf.init_buffer()
#pour le moment on garde les même threads qu'avant, mais au besoin, on les recréera !
class GameFrame(wx.Frame):
	def __init__( self, parent, ID, title,lon,lar,nm,th_E,th_R,pos=wx.DefaultPosition,size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE):
		wx.Frame.__init__(self, parent, ID, title, pos, size, style)
		self.SetAutoLayout(True)
		self.lon=10
		self.lar=10
		self.nm=3
#		self.name=name
#		self.host=host
#		self.port=port
		print "ici"
		self.th_E=th_E
		self.th_R=th_R
	#	self.GameWindow = DeminWindow(self,203,self.lon,self.lar,self.nm)
	#	self.GameWindow.init_buffer()
#		connexion = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#		try:
#			connexion.connect((self.host,self.port))
#			print "Connexion etablie avec le serveur."
#			self.parent.th_R = ThreadReception(self.parent,connexion)
#			self.parent.th_E = ThreadEmission(self.parent,connexion)
#			self.parent.th_E.start()
#			self.parent.th_R.start()
#		except socket.error:
#			print "La connexion a echoue."

#		
 #       #creation des espaces texte pour l'entree des differents parametres de connexion:
#		self.GameWindow = 0 #contiendra le deminWindow !




	






#	def sendmsg(self,event):
#		self.th_E.envoiM(event.GetString())
#		event.GetEventObject().Destroy()
#		tx4=wx.TextCtrl(self,3000,"",(60,130),size=(340,20),style=wx.TE_PROCESS_ENTER)
#		self.Bind(wx.EVT_TEXT_ENTER,self.sendmsg,tx4)
		
class PanInfApp(wx.App):
	def OnInit(self):
			win = PanInfFrame(None, 99, "Viva Argentina", size=(600, 650),style = wx.DEFAULT_FRAME_STYLE)
			win.Show(True)
			self.SetTopWindow(win)
			return True
class GameApp(wx.App):
	def __init__(self,lon,lar,nm,th_E,th_R):
		self.lon=lon
		self.lar=lar
		self.nm=nm
		self.th_E=th_E
		self.th_R=th_R
		wx.App.__init__(self)
		
	def OnInit(self):
			win2 = GameFrame(None, 301, "Viva Argentina",self.lon,self.lar,self.nm,self.th_E,self.th_R, size=(600, 650),style = wx.DEFAULT_FRAME_STYLE)
			win2.Show(True)
			self.SetTopWindow(win2)
			return True

class ThreadReception(threading.Thread): #objet thread gerant la reception des messages
    
    def __init__(self,fenetre,conn):
        threading.Thread.__init__(self)
	self.app=fenetre
	self.connexion= conn

        #self.connexion = conn # ref. du socket de connexion

    def run(self):
        while 1:
            msg_recu = self.connexion.recv(1024)
	    msg_recu=msg_recu.split(",")
	    print msg_recu
	    if msg_recu[0]=="" or msg_recu[0].upper()=="FIN":
		    break
	    if msg_recu[0]=="M":
		    print "*" + msg_recu[1] + "*"
	    if msg_recu[0]=="G":
		    lon=int(msg_recu[1])
		    lar=int(msg_recu[2])
		    nm=int(msg_recu[3])
		    self.app.panInf.grillerecue(lon,lar,nm)

	    if msg_recu[0]=="Gupdate":
		    for i in range(self.app.l):#on reconstruit la grille a partir de la nouvelle grille recue
			    for j in range(self.app.L):
				    self.app.grille[i,j]=int(msg_recu[j*lar+i+1])
		  #x  self.app.init_buffer()
	    if msg_recu[-1].split(".")[0]=="nbj":
#		    print(msg_recu[-1].split("."))
		    self.app.panInf.nbJ=msg_recu[-1].split(".")[1]
		    self.app.panInf.maxJ=msg_recu[-1].split(".")[2]
		  #  self.thNBJ.updateAffichage()
		    if int(self.app.panInf.nbJ)==int(self.app.panInf.maxJ):
			    if int(self.app.panInf.nbJ)!=0:
				    self.app.panInf.afficherStart()
        # Si on est sorti du while, on a recu un arrêt de la réception. Le thread <reception> se termine ici.
        # On force la fermeture du thread <emission> :
        if self.app.th_E<>0:
		self.app.th_E._Thread__stop()
        print "Client arrete. Connexion interrompue."
        self.connexion.close()




class ThreadEmission(threading.Thread): #objet thread gerant l'emission des messages
    
    def __init__(self,fenetre,conn):
        threading.Thread.__init__(self)
        self.connexion = conn # ref. du socket de connexion
	self.app = fenetre


    def envoiM(self,a):
	    self.connexion.send(a)
    def envoiFin(self):
	    self.connexion.send("FIN")
    def envoiclikD(self,x,y):
	    self.connexion.send("R, %d ,%d"%(int(x),int(y)))

    def envoiclikG(self,x,y):
	    self.connexion.send("L, %d ,%d"%(int(x),int(y)))
    def envoiOK(self):
	    self.connexion.send("OK")
    def needNbjoueurs(self):
	    self.connexion.send("nbj,1")
	    

# Programme principal - Etablissement de la connexion :
#faire deux main loop, un pour rentrer l'host, le port et le nom du joueur et l'autre pour le jeu
#connexion = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#try:
#    connexion.connect((FrameInit1.host, FrameInit1.port))
#except socket.error:
#    print "La connexion a echoue."
#    sys.exit()
#print "Connexion etablie avec le serveur."

app = PanInfApp()
app.MainLoop()
#th_E = ThreadEmission(app,connexion)
#th_R = ThreadReception(app,connexion)
#th_E.start()
#th_R.start()

